package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.constant.KillConstants;
import cn.itsource.ymcc.constant.RConst;
import cn.itsource.ymcc.domain.KillActivity;
import cn.itsource.ymcc.domain.KillCourse;
import cn.itsource.ymcc.dto.KillDto;
import cn.itsource.ymcc.dto.PreOrderDto;
import cn.itsource.ymcc.exception.GlobalException;
import cn.itsource.ymcc.mapper.KillActivityMapper;
import cn.itsource.ymcc.mapper.KillCourseMapper;
import cn.itsource.ymcc.result.JsonResult;
import cn.itsource.ymcc.service.IKillCourseService;
import cn.itsource.ymcc.utils.AssertUtil;
import cn.itsource.ymcc.utils.CodeGenerateUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zongcj
 * @since 2023-09-28
 */
@Service
public class KillCourseServiceImpl extends ServiceImpl<KillCourseMapper, KillCourse> implements IKillCourseService {
    @Autowired
    private KillActivityMapper killActivityMapper;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public boolean save(KillCourse entity) {
        entity.setPublishStatus(RConst.Num.INT_0);
        entity.setCreateTime(new Date());
        Long activityId = entity.getActivityId();
        KillActivity killActivity = killActivityMapper.selectById(activityId);
        entity.setStartTime(killActivity.getBeginTime());
        entity.setEndTime(killActivity.getEndTime());
        entity.setTimeStr(killActivity.getTimeStr());
        super.save(entity);
        return false;
    }

    @Override
    public JsonResult getKillCourse() {
        BoundHashOperations<String, Object, Object> map = redisTemplate.boundHashOps(KillConstants.KEY_KILL_COURSE);
        List<Object> values = map.values();
        return JsonResult.success().setData(values);
    }

    @Override
    public KillCourse getDetailKillCourse(Long id) {
        BoundHashOperations<String, Object, Object> map = redisTemplate.boundHashOps(KillConstants.KEY_KILL_COURSE);
        KillCourse o = (KillCourse)map.get(id.toString());
        return o;
    }

    @Override
    public JsonResult kill(KillDto killDto) {
        //从redis里面都没有了
        KillCourse killCourse = this.getDetailKillCourse(killDto.getKillCourseId());
        AssertUtil.isNotNull(killCourse,"非法请求");

        //防止用户重复购买
        Boolean aBoolean = redisTemplate.hasKey(KillConstants.KILL_RECORD + "_" + killDto.getLoginId() + "_" + killCourse.getId());
        AssertUtil.isFalse(aBoolean,"请勿重复秒杀同一课程！");


        //当前用户买的时间 一定要在规定时间内
        //秒杀时间是否合法
        Date date = new Date();
        AssertUtil.isTrue(date.after(killCourse.getStartTime()) && date.before(killCourse.getEndTime()), "秒杀活动时间不合法！");

        //用户购买的数量
        Long number = killDto.getNumber();
        AssertUtil.isTrue(number <= killCourse.getKillLimit(),"每人限购"+killCourse.getKillLimit()+"份！");

        //进行抢锁
        RSemaphore semaphore = redissonClient.getSemaphore(KillConstants.KILL_STORE + ":" + killDto.getKillCourseId());
        boolean b = semaphore.tryAcquire(number.intValue());
        String orderNo = "";
        if(b){//为true的情况下才下单---生成伪订单
            //伪下单
            //抢到了锁，扣减库存也成功了：
            //3. 创建订单号，准备“预创订单数据”
            orderNo = CodeGenerateUtils.generateOrderSn(killDto.getLoginId());
            //4. 保存“预创订单数据到Redis”   PreOrderDto：需要什么字段？依据是下订单需要哪些字段 就设置哪些字段
            PreOrderDto preOrderDto = new PreOrderDto();
            preOrderDto.setOrderNo(orderNo);
            preOrderDto.setUserId(killDto.getLoginId());
            preOrderDto.setTitle("秒杀订单");
            preOrderDto.setOrderType(1);
            preOrderDto.setPrice(killCourse.getKillPrice());
            preOrderDto.setCount(killDto.getNumber());
            preOrderDto.setCourseId(killCourse.getCourseId());
            preOrderDto.setCourseName(killCourse.getCourseName());
            preOrderDto.setCoursePic(killCourse.getCoursePic());
            preOrderDto.setKillCourseId(killCourse.getId());
            redisTemplate.opsForValue().set(KillConstants.KEY_PREFIX_PRE_ORDER+":"+orderNo, preOrderDto);
            //开启延迟消息   万一用户不支付  等等一些列情况


            //防止用户重复购买
            redisTemplate.opsForValue().set(KillConstants.KILL_RECORD+"_"+killDto.getLoginId()+"_"+killCourse.getId(), 1);
        }else {
            throw new GlobalException("秒杀失败");
        }
        return JsonResult.success().setData(orderNo);
    }
}
